package service

import (
	"backend/internal/config"
	"backend/pkg/blockchain"
	"encoding/json"
	"fmt"
	"github.com/pkg/errors"
	"log"
	"strconv"
)

type AssertService struct {
	client       *blockchain.Client
	chainConfigs map[string]config.ChainConfig
}

func NewAssertService(client *blockchain.Client, cfgs map[string]config.ChainConfig) *AssertService {
	return &AssertService{
		client:       client,
		chainConfigs: cfgs,
	}
}

// --------------- 基础工具方法 ---------------
func (s *AssertService) getChainConfig(chainID string) (config.ChainConfig, error) {
	cfg, exists := s.chainConfigs[chainID]
	if !exists {
		return config.ChainConfig{}, fmt.Errorf("chain ID %s not configured", chainID)
	}
	return cfg, nil
}

// service/assert_service.go

// buildArgs 确保正确处理参数
func (s *AssertService) buildArgs(funcName string, params ...string) [][]byte {
	args := make([][]byte, 0, len(params)+1)

	// 首先添加函数名
	args = append(args, []byte(funcName))

	// 然后添加所有参数
	for _, param := range params {
		args = append(args, []byte(param))
	}

	return args
}

func (s *AssertService) handleChainOperation(chainID string, op func() ([]byte, error)) ([]byte, error) {
	if _, err := s.getChainConfig(chainID); err != nil {
		return nil, err
	}
	return op()
}

// --------------- HTL 相关操作 ---------------
func (s *AssertService) CreateSenderHTL(chainID, clientID string, seed int64, timeout int, amount int, tokenID string) (string, error) {
	cfg, err := s.getChainConfig(chainID)
	if timeout < 60 {
		return "", errors.New("timeout must be at least 60 seconds")
	}

	args := s.buildArgs(
		"CreateSenderHTL",
		clientID,
		strconv.FormatInt(seed, 10),
		strconv.Itoa(timeout),
		strconv.Itoa(amount),
		tokenID,
	)

	resp, err := s.handleChainOperation(chainID, func() ([]byte, error) {
		return s.client.SubmitTransaction(chainID, cfg.Chaincodes.Assert.Name, args...)
	})
	return string(resp), errors.Wrap(err, "failed to create sender HTL")
}

func (s *AssertService) CreateReceiverHTL(chainID, hashValue, clientID string, timeout int, amount int, tokenID string) (string, error) {
	cfg, err := s.getChainConfig(chainID)
	if len(hashValue) != 64 {
		return "", errors.New("hash value must be 64 characters")
	}

	args := s.buildArgs(
		"CreateReceiverHTL",
		hashValue,
		clientID,
		strconv.Itoa(timeout),
		strconv.Itoa(amount),
		tokenID,
	)

	resp, err := s.handleChainOperation(chainID, func() ([]byte, error) {
		return s.client.SubmitTransaction(chainID, cfg.Chaincodes.Assert.Name, args...)
	})
	return string(resp), errors.Wrap(err, "failed to create receiver HTL")
}

func (s *AssertService) UnlockReceiverHTL(chainID, htlKey, preimage string) error {
	cfg, err := s.getChainConfig(chainID)
	args := s.buildArgs(
		"UnlockReceiverHTL",
		htlKey,
		preimage,
	)

	_, err = s.handleChainOperation(chainID, func() ([]byte, error) {
		return s.client.SubmitTransaction(chainID, cfg.Chaincodes.Assert.Name, args...)
	})
	return errors.Wrap(err, "failed to unlock receiver HTL")
}

func (s *AssertService) UnlockSenderHTL(chainID, htlKey, preimage string) error {
	cfg, err := s.getChainConfig(chainID)
	args := s.buildArgs(
		"UnlockSenderHTL",
		htlKey,
		preimage,
	)

	_, err = s.handleChainOperation(chainID, func() ([]byte, error) {
		return s.client.SubmitTransaction(chainID, cfg.Chaincodes.Assert.Name, args...)
	})
	return errors.Wrap(err, "failed to unlock sender HTL")
}

func (s *AssertService) RefundHTL(chainID, htlKey string) error {
	cfg, err := s.getChainConfig(chainID)
	args := s.buildArgs(
		"RefundHTL",
		htlKey,
	)

	_, err = s.handleChainOperation(chainID, func() ([]byte, error) {
		return s.client.SubmitTransaction(chainID, cfg.Chaincodes.Assert.Name, args...)
	})
	return errors.Wrap(err, "failed to refund HTL")
}

// --------------- 代币操作 ---------------
// service/assert_service.go

func (s *AssertService) MintToken(chainID string, amount int, tokenID string, clientID string) error {
	cfg, err := s.getChainConfig(chainID)
	if err != nil {
		return err
	}

	if amount <= 0 {
		return errors.New("mint amount must be positive")
	}

	if clientID == "" {
		return errors.New("clientID is required")
	}

	// 创建包含全部三个参数的调用
	args := s.buildArgs(
		"Mint",
		strconv.Itoa(amount),
		tokenID,
		clientID,
	)

	// 添加调试日志
	log.Printf("链 %s | Mint参数 [amount: %d, tokenID: %s, clientID: %s]",
		chainID, amount, tokenID, clientID)

	_, err = s.handleChainOperation(chainID, func() ([]byte, error) {
		return s.client.SubmitTransaction(chainID, cfg.Chaincodes.Assert.Name, args...)
	})

	// 使用errors.Wrap添加更多上下文信息
	return errors.Wrap(err, "failed to mint tokens")
}

func (s *AssertService) GetAllTokenBalances(chainID string) ([]TokenBalance, error) {
	cfg, err := s.getChainConfig(chainID)
	args := s.buildArgs("GetAllTokenBalances")

	resp, err := s.handleChainOperation(chainID, func() ([]byte, error) {
		return s.client.Evaluate(chainID, cfg.Chaincodes.Assert.Name, args...)
	})
	if err != nil {
		return nil, errors.Wrap(err, "failed to query balances")
	}

	var balances []TokenBalance
	if err := json.Unmarshal(resp, &balances); err != nil {
		return nil, errors.Wrap(err, "failed to parse balances")
	}

	return balances, nil
}

func (s *AssertService) CreateTokenBalances(chainID string, account *Account) error {
	cfg, err := s.getChainConfig(chainID)
	accountData, err := json.Marshal(account)
	if err != nil {
		return errors.Wrap(err, "failed to serialize account")
	}

	args := s.buildArgs(
		"CreateTokenBalances",
		string(accountData),
	)

	_, err = s.handleChainOperation(chainID, func() ([]byte, error) {
		return s.client.SubmitTransaction(chainID, cfg.Chaincodes.Assert.Name, args...)
	})
	return errors.Wrap(err, "failed to create token balances")
}

// --------------- 零知识证明相关 ---------------
func (s *AssertService) VerifyProof(chainID, proofStr string) error {
	cfg, err := s.getChainConfig(chainID)
	args := s.buildArgs(
		"VerifyProof",
		proofStr,
	)

	_, err = s.handleChainOperation(chainID, func() ([]byte, error) {
		return s.client.SubmitTransaction(chainID, cfg.Chaincodes.Assert.Name, args...)
	})
	return errors.Wrap(err, "proof verification failed")
}

func (s *AssertService) CreateProof(chainID, proofID, proofData string) error {
	cfg, err := s.getChainConfig(chainID)
	args := s.buildArgs(
		"CreateProof",
		proofID,
		proofData,
	)

	_, err = s.handleChainOperation(chainID, func() ([]byte, error) {
		return s.client.SubmitTransaction(chainID, cfg.Chaincodes.Assert.Name, args...)
	})
	return errors.Wrap(err, "failed to create proof")
}

func (s *AssertService) GetAllProofs(chainID string) ([]map[string]interface{}, error) {
	cfg, err := s.getChainConfig(chainID)
	args := s.buildArgs("GetAllProof")

	resp, err := s.handleChainOperation(chainID, func() ([]byte, error) {
		return s.client.Evaluate(chainID, cfg.Chaincodes.Assert.Name, args...)
	})
	if err != nil {
		return nil, errors.Wrap(err, "failed to query proofs")
	}

	var proofs []map[string]interface{}
	if err := json.Unmarshal(resp, &proofs); err != nil {
		return nil, errors.Wrap(err, "failed to parse proof data")
	}

	return proofs, nil
}

func (s *AssertService) VerifyAndSaveProof(chainID, proofID, proofData string) error {
	cfg, err := s.getChainConfig(chainID)
	args := s.buildArgs(
		"VerifySaveProof",
		proofID,
		proofData,
	)

	_, err = s.handleChainOperation(chainID, func() ([]byte, error) {
		return s.client.SubmitTransaction(chainID, cfg.Chaincodes.Assert.Name, args...)
	})
	return errors.Wrap(err, "failed to verify and save proof")
}

// --------------- 数据结构 ---------------
type TokenBalance struct {
	ClientID string `json:"clientID"`
	TokenID  string `json:"tokenID"`
	Balance  int    `json:"balance"`
}

type Account struct {
	Address string `json:"address"`
	Balance int    `json:"balance"`
	Nonce   int    `json:"nonce"`
}
